﻿using LibOfdDataExtractionParam;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfOfdDataExtractionClient
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void btnOfdDataExtract_Click(object sender, RoutedEventArgs e)
        {
            string[] fileNames = GetFileNameFromDlg(true);
            if (fileNames == null)
                return;

            string ofdFileName = fileNames.First();
            string url = txtWebServerUrl.Text;

            int dealCount = 1;
            int.TryParse(txtDrawCount.Text.Trim(), out dealCount);

            int threadCount;
            int.TryParse(txtThreadCount.Text, out threadCount);
            if (threadCount <= 0)
                threadCount = 1;

            OfdFileExtractAsyn(fileNames, url, dealCount, threadCount);
        }

        long _ofdDrawCount;
        private async void OfdFileExtractAsyn(string[] fileNames, string url, int dealCount, int threadCount)
        {
            if (dealCount <= 0)
                return;

            int totalCount = dealCount;
            threadCount = Math.Min(threadCount, dealCount);

            List<Task> taskGroup = new List<Task>();

            long ofdDrawCountThis = 0;
            DateTime startTime = DateTime.Now;

            for (int i = 0; i < threadCount; i++)
            {
                Task task = Task.Run(() =>
                {
                    try
                    {
                        while (totalCount > 0)
                        {
                            lock (this)
                            {
                                _ofdDrawCount++;
                                ofdDrawCountThis++;
                                totalCount--;
                            }

                            OfdExtractionOutput ofdExtractionOutput = OfdFileDataExtract(fileNames, url);
                            DealOutputResult(ofdExtractionOutput);
                        }
                    }
                    catch (Exception ex)
                    {
                        AddLog(ex.Message);
                    }
                });

                taskGroup.Add(task);
            }

            await Task.WhenAll(taskGroup.ToArray());

            TimeSpan span = DateTime.Now - startTime;
            double speed = ofdDrawCountThis / span.TotalSeconds;

            txtOfdCreateSpeedTotal.Text = string.Format("本次 运行时长: {0}秒 速度: {1} 个/秒",
                span.TotalSeconds.ToString("f2"), speed.ToString("f2"));
        }

        private void DealOutputResult(OfdExtractionOutput ofdExtractionOutput)
        {

        }

        private OfdExtractionOutput OfdFileDataExtract(string[] fileNames, string url)
        {
            DateTime start = DateTime.Now;

            OfdExtractionInput extractionInput = ToOfdExtractionInput(fileNames);
            OfdExtractionOutput extractionOutput = OfdFileToPdf(extractionInput, url);

            foreach (OfdDataExtractionInfo file in extractionOutput.ListOfdFileInfo)
            {
                if (!file.OK)
                {
                    AddLog(string.Format("{0} 提取失败！{1}", file.FileName, file.Message));
                }
            }

            int ms = (int)(DateTime.Now - start).TotalMilliseconds;
            AddLog(string.Format("处理结束! 耗时:{0}毫秒", ms), extractionOutput);
            return extractionOutput;
        }

        private OfdExtractionInput ToOfdExtractionInput(string[] fileNames)
        {
            OfdExtractionInput extractionInput = new OfdExtractionInput();
            extractionInput.ClientData = "数据提取测试";
            foreach (string fileName in fileNames)
            {
                string fileDataBase64 = Convert.ToBase64String(System.IO.File.ReadAllBytes(fileName));

                OfdExtractionFileInput fileInfo = new OfdExtractionFileInput();
                fileInfo.FileName = System.IO.Path.GetFileNameWithoutExtension(fileName);
                fileInfo.OfdFileID = Guid.NewGuid().ToString();
                fileInfo.OfdFileDataBase64 = fileDataBase64;

                fileInfo.OfdFileType = "增值税电子普通发票";
                fileInfo.DataExtractionType = "票面信息";
                extractionInput.ListOfdFileInput.Add(fileInfo);
            }
            return extractionInput;
        }

        public OfdExtractionOutput OfdFileToPdf(OfdExtractionInput inputParam, string httpUrl)
        {
            string jsonText = JsonConvert.SerializeObject(inputParam);

            NameValueCollection postParam = new NameValueCollection();
            postParam.Add("input", jsonText);

            WebClient webClient = new WebClient();
            byte[] data = webClient.UploadValues(httpUrl, "POST", postParam);
            string strData = Encoding.UTF8.GetString(data);

            OfdExtractionOutput ofdOutputParam = JsonConvert.DeserializeObject<OfdExtractionOutput>(strData);

            return ofdOutputParam;
        }

        void AddLog(string message, OfdExtractionOutput ofdData = null)
        {
            if (!_isShowLog)
                return;

            this.Dispatcher.Invoke(() => AddLogInner(message, ofdData));
        }

        void AddLogInner(string message, OfdExtractionOutput ofdData)
        {
            LogMessage2 logMessage = new LogMessage2() { Str = new string[3] };
            logMessage.Str[0] = (ListLogInfo.Items.Count + 1).ToString();
            logMessage.Str[1] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            logMessage.Str[2] = message;
            logMessage.Tag = ofdData;
            ListLogInfo.Items.Add(logMessage);
        }

        bool _isShowLog = true;
        private void checkShowLog_Click(object sender, RoutedEventArgs e)
        {
            _isShowLog = checkShowLog.IsChecked == true;
        }

        string[] GetFileNameFromDlg(bool multiselect)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.Multiselect = multiselect;
            ofd.Filter = "ofd|*.ofd;*.zip;|All Files (*.*)|*.*||";
            if (ofd.ShowDialog() == true)
            {
                return ofd.FileNames;
            }

            return null;
        }

        private void ListLogInfo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            LogMessage2 logMessage = ListLogInfo.SelectedItem as LogMessage2;
            if (logMessage == null)
                return;

            OfdExtractionOutput ofdData = logMessage.Tag as OfdExtractionOutput;
            if (ofdData == null)
                return;

            string message = string.Empty;
            int i = 0;
            foreach (OfdDataExtractionInfo info in ofdData.ListOfdFileInfo)
            {
                i++;
                if (!string.IsNullOrEmpty(message))
                {
                    message += "\r\n\r\n";
                }
                message += string.Format("************第{0}个文件({1})*************\r\n", i, info.FileName);

                message += GetInvoiceData(info.DataExtraction);
            }
            txtOfdData.Text = message;

        }

        private void MenuItemOfLog_Click(object sender, RoutedEventArgs e)
        {
            MenuItem item = sender as MenuItem;
            if (item.Tag == null)
                return;

            ListView listItem = this.FindName(item.Tag.ToString()) as ListView;
            if (listItem == null)
                return;

            ListViewHelper helper = new ListViewHelper(listItem);

            string cmdTxt = item.Header.ToString();
            helper.ListViewMenuCmd(cmdTxt);
        }

        private string GetInvoiceData(string dataExtraction)
        {
            try
            {
                InvoiceData invoiceData = JsonConvert.DeserializeObject<InvoiceData>(dataExtraction);

                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("开票类型: {0}\r\n", invoiceData.TypeCode == "0" ? "正数发票" : "负数发票");
                sb.AppendFormat("发票代码: {0}\r\n", invoiceData.InvoiceCode);
                sb.AppendFormat("发票号码: {0}\r\n", invoiceData.InvoiceNo);
                sb.AppendFormat("开票日期: {0}\r\n", invoiceData.IssueDate);
                sb.AppendFormat("校验码: {0}\r\n", invoiceData.InvoiceCheckCode);
                sb.AppendLine();

                sb.AppendFormat("二维码: {0}\r\n", invoiceData.GraphCode);
                sb.AppendFormat("机器编号: {0}\r\n", invoiceData.MachineNo);
                sb.AppendFormat("密码区: {0}\r\n", invoiceData.TaxControlCode);
                sb.AppendFormat("发票特殊标识区域1: {0}\r\n", invoiceData.InvoiceSIA1);
                sb.AppendFormat("发票特殊标识区域2: {0}\r\n", invoiceData.InvoiceSIA2);
                sb.AppendLine();

                sb.AppendFormat("收款人: {0}\r\n", invoiceData.Payee);
                sb.AppendFormat("复核: {0}\r\n", invoiceData.Checker);
                sb.AppendFormat("开票人: {0}\r\n", invoiceData.InvoiceClerk);
                sb.AppendLine();

                sb.AppendFormat("合计金额: {0}\r\n", invoiceData.TaxExclusiveTotalAmount);
                sb.AppendFormat("合计税额: {0}\r\n", invoiceData.TaxTotalAmount);
                sb.AppendFormat("备注: {0}\r\n", invoiceData.Note);
                sb.AppendLine();

                sb.AppendFormat("---------销售方信息------------\r\n");
                InvoiceSeller Seller = invoiceData.Seller;
                sb.AppendFormat("名称: {0}\r\n", Seller.SellerName);
                sb.AppendFormat("纳税人识别号: {0}\r\n", Seller.SellerTaxID);
                sb.AppendFormat("地址、电话: {0}\r\n", Seller.SellerAddrTel);
                sb.AppendFormat("开户行及账号: {0}\r\n", Seller.SellerFinancialAccount);
                sb.AppendLine();

                sb.AppendFormat("---------购买方信息------------\r\n");
                InvoiceBuyer Buyer = invoiceData.Buyer;
                sb.AppendFormat("名称: {0}\r\n", Buyer.BuyerName);
                sb.AppendFormat("纳税人识别号: {0}\r\n", Buyer.BuyerTaxID);
                sb.AppendFormat("地址、电话: {0}\r\n", Buyer.BuyerAddrTel);
                sb.AppendFormat("开户行及账号: {0}\r\n", Buyer.BuyerFinancialAccount);
                sb.AppendLine();

                if (invoiceData.GoodsInfos != null)
                {
                    sb.AppendFormat("---------货物清单------------\r\n");
                    int index = 0;
                    foreach (InvoiceGoodsInfo goodsInfo in invoiceData.GoodsInfos)
                    {
                        index++;
                        sb.AppendFormat("***序号: {0}\r\n", index);
                        sb.AppendFormat("项目名称: {0}\r\n", goodsInfo.Item);
                        sb.AppendFormat("规格型号: {0}\r\n", goodsInfo.Specification);
                        sb.AppendFormat("单位: {0}\r\n", goodsInfo.MeasurementDimension);
                        sb.AppendFormat("数量: {0}\r\n", goodsInfo.Quantity);
                        sb.AppendFormat("单价: {0}\r\n", goodsInfo.Price);
                        sb.AppendFormat("金额: {0}\r\n", goodsInfo.Amount);
                        sb.AppendFormat("税率: {0}\r\n", goodsInfo.TaxScheme);
                        sb.AppendFormat("税额: {0}\r\n", goodsInfo.TaxAmount);
                        sb.AppendLine();
                    }
                }

                return sb.ToString();
            }
            catch (Exception ex)
            {
                return dataExtraction;
            }
        }

    }

    public class LogMessage2
    {
        public string[] Str { get; set; }
        public object Tag { get; set; }
    }

}
